package Test;


import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.Date;
import java.util.ArrayList;

import javax.imageio.ImageIO;

import RSA.*;


public class Test {

	public static void main(String[] args) {
		String chaine = "Bonjour";
		KeyPairGenerator kpg = new KeyPairGenerator(256);
		Key publick = kpg.getPublicKey();
		Key privatek = kpg.getPrivateKey();
		
		
		
		byte[] chaineBytes = chaine.getBytes();
		BigInteger[] chaineBigIntegers = RSA.getBigIntegerArrayFromBytes(chaineBytes);
		
		
		BigInteger[] chaineBigIntegersEncrypted = Cipher.Encrypt(chaineBigIntegers, publick);
		byte[] chaineBytesEncrypted = Cipher.Encrypt(chaineBytes,publick);
		//BigInteger[] chaineBigIntegersDecrypted = Cipher.Decrypt(RSA.getBigIntegerArrayFromBytes(chaineBytesEncrypted), privatek);
		
		BigInteger[] chaineBigIntegersDecrypted = Cipher.Decrypt(chaineBigIntegersEncrypted, privatek);
		byte[] chaineBytesDecrypted = Cipher.Decrypt(chaineBytesEncrypted, privatek);
		
		System.out.println("chaineBytes");
		afficheBytes(chaineBytes);
		System.out.println("chaineBigIntegers");
		afficheBigIntegers(chaineBigIntegers);
		System.out.println("chaineBigIntegersEncrypted");
		afficheBigIntegers(chaineBigIntegersEncrypted);
		System.out.println("getBytes from chaineBigIntegersEncrypted");
		afficheBytes(RSA.getBytesFromBigIntegerArray(chaineBigIntegersEncrypted));
		System.out.println("chaineBigIntegersDecrypted");
		afficheBigIntegers(chaineBigIntegersDecrypted);
		System.out.println("getBytes from chaineBigIntegersDecrypted");
		afficheBytes(RSA.getBytesFromBigIntegerArray(chaineBigIntegersDecrypted));
		
		System.out.println("chaineBytesEncrypted");
		afficheBytes(chaineBytesEncrypted);
		System.out.println("chaineBytesDecrypted");
		afficheBytes(chaineBytesDecrypted);
		System.out.println(RSA.getStringFromBytes(chaineBytesDecrypted));
		
		System.out.println("===========================");
		System.out.println(RSA.getStringFromBytes(RSA.getBytesFromBigInteger(RSA.getBigIntegerFromBytes(chaineBytes))));
		
		BigInteger B = RSA.getBigIntegerFromBytes(chaineBytes);
		BigInteger Bc = Cipher.EncryptToBigInt(B, publick);
		BigInteger Bd = Cipher.DecryptToBigInt(Bc, privatek);
		System.out.println("Public :"+publick);
		System.out.println("Private :"+privatek);
		System.out.println(B+" "+Bc+" "+Bd);
		
		byte[] x =null;
		
		/*
		try {
			FileInputStream ips=new FileInputStream("/home/etudiant/Images/droid.png");
			
			byte[] c = new byte[1];
			    ArrayList<Byte> tab = new ArrayList<Byte>();
			    while(ips.read(c) != -1) {
			        tab.add(new Byte(c[0]));
			    }
			x = tab.toArray(new Byte[tab.size()]);
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		*/
		File fnew=new File("/home/etudiant/Images/pixel.png");
		
		BufferedImage originalImage;
		try {
			originalImage = ImageIO.read(fnew);
			ByteArrayOutputStream baos=new ByteArrayOutputStream();
			ImageIO.write(originalImage, "png", baos );
			byte[] imageInByte=baos.toByteArray();
			x = imageInByte;
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
/*
		File imgPath = new File("/home/etudiant/Images/droid.png");
		 BufferedImage bufferedImage = null;
		try {
			bufferedImage = ImageIO.read(imgPath);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		 // get DataBufferBytes from Raster
		 WritableRaster raster = bufferedImage.getRaster();
		 DataBufferByte data   = (DataBufferByte) raster.getDataBuffer();

		 x = data.getData();
*/		
		afficheBytes(x);
		System.out.println("Length of x:"+x.length);
		RSA r = new RSA(512);
		long depart = new Date().getTime();
		
		byte[] xc = r.Encrypt(x);
		System.out.println("Length of xc:"+xc.length);
		long fin = new Date().getTime();
		System.out.println("Encryption took :"+(fin-depart)+" ms");
		
		depart = new Date().getTime();
		byte[] xd = r.Decrypt(xc);
		System.out.println("Length of xd before:"+xd.length);
		afficheBytes(xc);
		afficheBytes(xd);
		xd = reduce(xd);
		System.out.println("Length of xd after:"+xd.length);
		fin = new Date().getTime();
		System.out.println("Decryption took :"+(fin-depart)+" ms");
		//afficheBytes(x);
		//afficheBytes(xc);
		afficheBytes(xd);
		
		File f = new File("test.png");
		
		try {
			FileOutputStream fos = new FileOutputStream("test.png");
			fos.write(xd);
			fos.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		 
	}
	
	public static byte[] toBytes(Byte[] b)
	{
		byte[] a = new byte[b.length];
		for(int i=0; i<b.length; i++)
		{
			a[i] = b[i].byteValue();
		}
		return a;
	}
	
	public static void afficheBytes(Byte[] b)
	{
		for(int i=0; i<b.length; i++)
		{
			System.out.print(b[i]+" ");
		}
		System.out.println();
	}
	
	public static void afficheBytes(byte[] b)
	{
		for(int i=0; i<b.length; i++)
		{
			System.out.print(b[i]+" ");
		}
		System.out.println();
	}
	
	public static void afficheBigIntegers(BigInteger[] b)
	{
		for(int i=0; i<b.length; i++)
		{
			System.out.print(b[i]+" ");
		}
		System.out.println();
	}
	
	public static byte[] reduce(byte[] b)
	{
		 //System.out.println("Length of b ="+b.length);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ByteArrayInputStream bais = new ByteArrayInputStream(b);
        int size = 512/4;
        byte[] buffer = new byte[size]; ;
        
		try {
		
	        	while (bais.read(buffer) != -1) 
	        	{
		            baos.write(reduceOne(buffer));
		            
		            //for(int i=0;i<8;i++) System.out.println(buffer[i]);
		            buffer = new byte[size];
		        }
	        //}
	       // System.out.println();
		} catch (Exception e) {
			e.printStackTrace();
		} 
        
        
        buffer = baos.toByteArray();
       //System.out.println("Length of buffer:"+buffer.length);
       int count=0;
       for(int k=buffer.length-1;k>=0;k--)
       {
    	   if(buffer[k]==(byte)0) count++;
    	   else break;
       }
       byte[] result = new byte[buffer.length-count];
       for(int k=0;k<result.length;k++)
       {
    	   result[k] = buffer[k];
       }
       return result;
	}
	public static int count=1;
	public static byte[] reduceOne(byte[] b)
	{
		
		ArrayList<Byte> al = new ArrayList<Byte>();
		int i=0;
		while(i<(b.length-8) && b[i]==0) i++;
		for(int j=i;j<b.length;j++)
		{
			 al.add(b[j]);
		}
		//al.add((byte)12);
		byte[] a = new byte[al.size()];
		for(int j=0;j<a.length;j++)
		{
			a[j] = al.get(j).byteValue();
		}
		return a;
	}
	

}
